import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;

import javax.swing.JFrame;

public class DijagramStanja extends JFrame {

    int visina_frejma = 600;
    int sirina_frejma = 1000;
    private int n = Koder.broj_celija - 1;
    private Krug[] kolekcija;
    private int izabrani_cvor;
    static boolean izabrano = false;

    public DijagramStanja() {
	super("Dijagram stanja");
	this.setSize(sirina_frejma, visina_frejma);
	this.setResizable(false);
	this.setLocation(100, 100);
	this.setDefaultCloseOperation(EXIT_ON_CLOSE);
	this.addMouseListener((MouseListener) new DijagramStanja.clickListener());
	this.setVisible(true);
    }

    static String toBin(int broj, int broj_dec) {
	String s = Integer.toBinaryString(broj);
	String result = "";
	int n = s.length();
	if (n < broj_dec) {
	    for (int i = 0; i < (broj_dec - n); i++) {
		result = result.concat("0");
	    }
	}
	result = result.concat(s);
	return result;
    }

    private class clickListener extends MouseAdapter {
	public void mouseClicked(MouseEvent event) {

	    int x = DijagramStanja.this.getMousePosition().x;
	    int y = DijagramStanja.this.getMousePosition().y;
	    for (int i = 0; i < (int) Math.pow(2, n); i++) {
		if (Point2D.distance(x, y, kolekcija[i].dajCentar().x, kolekcija[i].dajCentar().y) < kolekcija[i].radius / 2) {
		    izabrano = true;
		    izabrani_cvor = i;
		    DijagramStanja.this.repaint(0, 0, visina_frejma, visina_frejma);
		    DijagramStanja.this.repaint(800, 245, 200, 25);
		}
	    }
	}
    }

    public void paint(Graphics g) {
	Graphics2D g2 = (Graphics2D) g;
	if (isOpaque()) { // paint background
	    GradientPaint gp = new GradientPaint(0, visina_frejma, Color.blue, sirina_frejma, 0, Color.white);
	    g2.setPaint(gp);
	    g.fillRect(0, 0, sirina_frejma, visina_frejma);
	}
	n = Koder.broj_celija - 1;
	Krug[] kolekcija = crtajKrugove((int) Math.pow(2, n));
	int x = 600;
	int y = 220;
	crtajBox(x, y - 2);
	if (izabrano) {
	    crtajKrive(izabrani_cvor);
	    puniBox(x, y);
	}
    }

    private void crtajKrive(int i) {
	new Kriva(kolekcija[i], kolekcija[Integer.parseInt(Koder.tranzicija[i][0], 2)], 0);
	new Kriva(kolekcija[i], kolekcija[Integer.parseInt(Koder.tranzicija[i][1], 2)], 1);
    }

    private Krug[] crtajKrugove(int n) {
	Graphics2D g2 = (Graphics2D) DijagramStanja.this.getGraphics();
	int r = 250;
	kolekcija = new Krug[n];
	for (int i = 0; i < n; i++) {
	    double x = Math.cos(i * 2 * Math.PI / n) * r + visina_frejma / 2;
	    double y = Math.sin(i * 2 * Math.PI / n) * r + visina_frejma / 2;
	    kolekcija[i] = new Krug(new Point2D.Double(x, y));

	    x = Math.cos(i * 2 * Math.PI / n) * (r - kolekcija[i].radius / 2 - 1) + visina_frejma / 2;
	    y = 0 - Math.sin(i * 2 * Math.PI / n) * (r - kolekcija[i].radius / 2 - 1) + visina_frejma / 2;
	    kolekcija[i].cross = new Point2D.Double(x, y);

	    x = Math.cos(i * 2 * Math.PI / n + Math.PI / 180) * (r - kolekcija[i].radius / 2 - 10) + visina_frejma / 2;
	    y = 0 - Math.sin(i * 2 * Math.PI / n + Math.PI / 180) * (r - kolekcija[i].radius / 2 - 10) + visina_frejma
		    / 2;
	    kolekcija[i].arrowPoint_1 = new Point2D.Double(x, y);

	    x = Math.cos(i * 2 * Math.PI / n - Math.PI / 180) * (r - kolekcija[i].radius / 2 - 10) + visina_frejma / 2;
	    y = 0 - Math.sin(i * 2 * Math.PI / n - Math.PI / 180) * (r - kolekcija[i].radius / 2 - 10) + visina_frejma
		    / 2;
	    kolekcija[i].arrowPoint_2 = new Point2D.Double(x, y);
	    if (i == 0) {
		kolekcija[i].ID = i;
	    } else {
		kolekcija[i].ID = n - i;
	    }
	    kolekcija[i].oznaci();
	}
	return kolekcija;
    }

    private class Krug {
	Graphics2D g2 = (Graphics2D) DijagramStanja.this.getGraphics();
	private Ellipse2D.Double e;
	public Point2D.Double centar, cross, arrowPoint_1, arrowPoint_2;
	public int radius = 30;
	public int ID;

	public Krug(Point2D.Double p) {
	    e = new Ellipse2D.Double(p.x - radius / 2, p.y - radius / 2, radius, radius);
	    centar = p;
	    g2.setPaint(Color.white);
	    g2.setStroke(new BasicStroke(1));
	    g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_FRACTIONALMETRICS,
		    RenderingHints.VALUE_FRACTIONALMETRICS_ON));
	    g2.draw(e);
	    g2.setPaint(Color.white);
	    g2.fill(e);
	}

	public void oznaci() {
	    Font font = new Font("Arial", Font.TYPE1_FONT, 20);
	    g2.setFont(font);
	    g2.setColor(Color.black);
	    g2
		    .setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
			    RenderingHints.VALUE_ANTIALIAS_ON));
	    if (ID < 10) {
		g2.drawString("" + ID, (float) this.centar.x - 6, (float) this.centar.y + 7);
	    } else {
		g2.drawString("" + ID, (float) this.centar.x - 13, (float) this.centar.y + 7);
	    }
	}

	public Point2D.Double dajCentar() {
	    Point2D.Double p;
	    p = kolekcija[this.ID].centar;
	    return p;
	}
    }

    private class Kriva {
	Graphics2D g2 = (Graphics2D) DijagramStanja.this.getGraphics();
	private QuadCurve2D.Double e;
	public Point2D.Double start, kraj;

	public Kriva(Krug k1, Krug k2, int bit) {
	    e = new QuadCurve2D.Double(k1.cross.x, k1.cross.y, 300, 300, k2.cross.x, k2.cross.y);
	    g2.setStroke(new BasicStroke(2));
	    if (bit == 0) {
		g2.setPaint(Color.YELLOW);
	    } else if (bit == 1) {
		g2.setPaint(Color.RED);
	    } else {
		g2.setPaint(Color.BLACK);
		g2.setStroke(new BasicStroke(1));
	    }

	    g2
		    .setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
			    RenderingHints.VALUE_ANTIALIAS_ON));
	    g2.draw(e);

	    g2.drawLine((int) k2.arrowPoint_1.x, (int) k2.arrowPoint_1.y, (int) k2.cross.x, (int) k2.cross.y);
	    g2.drawLine((int) k2.arrowPoint_2.x, (int) k2.arrowPoint_2.y, (int) k2.cross.x, (int) k2.cross.y);
	}
    }

    private void crtajBox(int x, int y) {
	Graphics2D g2 = (Graphics2D) DijagramStanja.this.getGraphics();
	// g2.drawRect(x, y, 300, 400);
	g2.drawRect(x, y, 370, 40);
	g2.drawRect(x, y, 185, 160);
	g2.drawRect(x, y + 40, 370, 40);
	g2.drawRect(x, y + 80, 370, 40);
	g2.drawRect(x, y + 120, 370, 40);
	g2.drawRect(x, y + 40, 70, 120);
	Font font = new Font("Courier", Font.TYPE1_FONT, 20);
	g2.setFont(font);
	g2.setColor(Color.black);
	// g2.setRenderingHints(new
	// RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON));
	g2.drawString("Aktivno stanje", x + 10, y + 25);
	g2.drawString("Ulaz", x + 10, y + 65);
	g2.drawString("Izlaz", x + 100, y + 65);
	g2.drawString("Naredno stanje", x + 195, y + 65);
	g2.setColor(Color.yellow);
	g2.drawString("0", x + 30, y + 105);
	g2.setColor(Color.red);
	g2.drawString("1", x + 30, y + 145);
    }

    private void puniBox(int x, int y) {
	Graphics2D g2 = (Graphics2D) DijagramStanja.this.getGraphics();
	Font font = new Font("Courier", Font.TYPE1_FONT, 20);
	g2.setFont(font);
	g2.setColor(Color.black);
	g2.drawString(DijagramStanja.toBin(izabrani_cvor, n), x + 260, y + 25);
	g2.drawString(Koder.izlaz[izabrani_cvor][0], x + 115, y + 105);
	g2.drawString(Koder.izlaz[izabrani_cvor][1], x + 115, y + 145);
	g2.drawString(Koder.tranzicija[izabrani_cvor][0], x + 260, y + 105);
	g2.drawString(Koder.tranzicija[izabrani_cvor][1], x + 260, y + 145);
    }
}
